package Lexico;

import java.io.IOException;
import FileManager.ManejadorArchivo;
import Mensajes.Mensaje;
import TablaDeSimbolos.TSimbolo;
import TokensDelLenguaje.Tokens;
import TokensDelLenguaje.Token;
import TokensDelLenguaje.Token_Cadena;
import TokensDelLenguaje.Token_Identificador;
import TokensDelLenguaje.Token_Uinteger;
import TokensDelLenguaje.Token_Ulongint;


public class AccionSemantica {
    AnalizadorLexico analizadorLexico;
    ManejadorArchivo managerArchivo;
    TSimbolo ts;
    String buffer;

    public AccionSemantica(ManejadorArchivo ma, AnalizadorLexico al, TSimbolo ts){
        this.analizadorLexico = al;
        this.managerArchivo = ma;
        this.ts = ts;
        buffer = new String("");
    }

    public Token ejecutarASemantica(char caracter, int num_proceso) throws IOException{
        if(caracter == '\n')
            analizadorLexico.incrementar_num_lineas();
        if(num_proceso == 0)
            return null;
        else if(num_proceso == 1)
            return semantica_1(caracter);
        else if(num_proceso == 2)
            return semantica_2(caracter);
        else if(num_proceso == 3)
            return semantica_3(caracter);
        else if(num_proceso == 4)
            return semantica_4();
        else if(num_proceso == 5)
            return semantica_5();
        else if(num_proceso == 6)
            return semantica_6();
        else if(num_proceso == 7)
            return semantica_7();
        else if(num_proceso == 8)
            return semantica_8(caracter);
        else if(num_proceso == 9)
            return semantica_9(caracter);
        else if(num_proceso == 10)
            return semantica_10(caracter);
        else if(num_proceso == 11)
            return semantica_11();
        else if(num_proceso == 12)
            return semantica_12(caracter);
        else if(num_proceso == 13)
            return semantica_13(caracter);
        else if(num_proceso == 20)
            return semantica_20();
        else if(num_proceso == 21)
            return semantica_21(caracter);
        else if(num_proceso == 22)
            return semantica_22();
        else if(num_proceso == 23)
            return semantica_23(caracter);
        else if(num_proceso == 24)
            return semantica_24(caracter);
        else if(num_proceso == 25)
            return semantica_25(caracter);
        else if(num_proceso == 26)
            return semantica_26(caracter);
        else
            procesoErrorLexico(caracter);
     return null;
    }

    private Token semantica_1(char caracter){
        agregarCaracter(caracter);
        return null;
    }

    private Token semantica_2(char caracter) throws IOException{
        Token t;
        retroceder_archivo(caracter);
        String buffer_temp = buffer.toLowerCase();
        if(buffer_temp.equals("if"))
            t = new Token(Tokens.rsv_if);
        else if(buffer_temp.equals("else"))
            t = new Token(Tokens.rsv_else);
        else if(buffer_temp.equals("then"))
            t = new Token(Tokens.rsv_then);
        else if(buffer_temp.equals("for"))
            t = new Token(Tokens.rsv_for);
        else if(buffer_temp.equals("print"))
            t = new Token(Tokens.rsv_print);
        else if(buffer_temp.equals("struct"))
            t = new Token(Tokens.rsv_struct);
        else if (buffer_temp.equals("ulongint"))
            t = new Token(Tokens.rsv_ulongint);
        else if (buffer_temp.equals("uinteger"))
            t = new Token(Tokens.rsv_uinteger);
        else if (buffer_temp.equals("begin"))
            t = new Token(Tokens.rsv_begin);
        else if (buffer_temp.equals("end"))
            t = new Token(Tokens.rsv_end);
        else{
            t = new Token_Identificador(buffer);
            ts.put(t);
            if(buffer.length() > Token_Identificador.MAX_VAR)
                analizadorLexico.informe("ADVERTENCIA: linea " + analizadorLexico.get_num_lineas() + " - Variable \'" + buffer + "\' se trunca a \'" + t.getCadena() + "\'.", Mensaje.INF);
        }
        vaciarBuffer();
        return t;
    }

    private Token semantica_3(char caracter){
        Token t = null;
        if(caracter == '{')
            t = new Token(Tokens.llave_abre);
        else if(caracter == '}')
            t = new Token(Tokens.llave_cierra);
        else if(caracter == ')')
            t = new Token(Tokens.parentesis_cierra);
        else if(caracter == '*')
            t = new Token(Tokens.asterisco);
        else if(caracter == ',')
            t = new Token(Tokens.coma);
        else if(caracter == ';')
            t = new Token(Tokens.punto_y_coma);
        else if(caracter == '.')
            t = new Token(Tokens.punto);
        else if(caracter == '-')
            t = new Token(Tokens.resta);
        else if(caracter == '+')
            t = new Token(Tokens.suma);
        else if(caracter == '/')
            t = new Token(Tokens.division);
        return t;
    }

    private Token semantica_4() throws IOException{
        vaciarBuffer();
        return new Token(Tokens.menor_igual);
    }

    private Token semantica_5() throws IOException{
        eliminarUltimoCaracter();
        String comentario = buffer.substring(2);
        analizadorLexico.informe("\n--- INICIO DE COMENTARIO ---\n" + comentario + "\n--- FIN DE COMENTARIO (linea " + analizadorLexico.get_num_lineas() + ") ---\n", Mensaje.INF);
        vaciarBuffer();
        return null;
    }

    private Token semantica_6(){
        vaciarBuffer();
        return new Token(Tokens.asignacion);
    }

    private Token semantica_7(){
        vaciarBuffer();
        return new Token(Tokens.mayor_igual);
    }

    private Token semantica_8(char caracter) throws IOException{
        retroceder_archivo(caracter);
        vaciarBuffer();
        return new Token(Tokens.mayor);
    }

    private Token semantica_9(char caracter){
        agregarCaracter(caracter);
        char c = buffer.charAt(0);
        vaciarBuffer();
        if(c == '=')
            return new Token(Tokens.igual);
        else
            if(c == '!')
                return new Token(Tokens.distinto);
        return new Token(Tokens.ilegal);
    }

    private Token semantica_10(char caracter) throws IOException{
        retroceder_archivo(caracter);
        vaciarBuffer();
        return new Token(Tokens.menor) ;
    }

    private Token semantica_11(){
        Token t = new Token_Cadena(buffer.substring(1));
        ts.put(t);
        vaciarBuffer();
        return t;
    }

    private Token semantica_12(char caracter){
        agregarCaracter(caracter);
        String token = buffer.substring(0, buffer.length()-2);
        Token t = null;
        if(caracter == 'l')
            t = new Token_Ulongint(Long.valueOf(token));
        else if (caracter == 'i')
            t = new Token_Uinteger(Long.valueOf(token));
        if (t.getLong() == null){
            t = null;
            analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Valor de Constante fuera de rango.", Mensaje.INF);
        }
        else
            ts.put(t);
        vaciarBuffer();
        return t;
    }

    private Token semantica_13(char caracter) throws IOException{
        retroceder_archivo(caracter);
        vaciarBuffer();
        return new Token(Tokens.parentesis_abre);
    }


    private Token semantica_20() throws IOException {
      vaciarBuffer();
      analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Se esperaba UL o UI al final de la constante.", Mensaje.INF);
      return null;
    }

    private Token semantica_21(char caracter) throws IOException{
      retroceder_archivo(caracter);
      vaciarBuffer();
      analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Se esperaba = luego del caracter :", Mensaje.INF);
      return null;
    }

    private Token semantica_22() throws IOException {
      vaciarBuffer();
      analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Las cadenas de caracteres no pueden tener mas de una línea.", Mensaje.INF);
      return null;
    }
    
    private Token semantica_23(char caracter) throws IOException {
      retroceder_archivo(caracter);
      analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Se esperaba el caracter = luego del caracter " + buffer.charAt(0), Mensaje.INF);
      vaciarBuffer();
      return null;
    }
    
    private Token semantica_24(char caracter) throws IOException {
      retroceder_archivo(caracter);
      analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Se esperaban *) como cierre del comentario.", Mensaje.INF);
      vaciarBuffer();
      return null;
    }
    
    private Token semantica_25(char caracter) throws IOException {
      retroceder_archivo(caracter);
      analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Se esperaban ) como cierre del comentario.", Mensaje.INF);
      vaciarBuffer();
      return null;
    }
    
    private Token semantica_26(char caracter) throws IOException {
      retroceder_archivo(caracter);
      analizadorLexico.informe("linea " + analizadorLexico.get_num_lineas() + " - Se esperaban ' como cierre de la cadena de caracteres.", Mensaje.INF);
      vaciarBuffer();
      return null;
    }

    private void procesoErrorLexico(char caracter){
        vaciarBuffer();
        if(caracter == '\n'){
            analizadorLexico.informe("linea " + (analizadorLexico.get_num_lineas() - 1) + " - Caracter \" " + Clasificador.traducir(caracter) + " \" (# " + (int)caracter + ") no válido.", Mensaje.INF);
            }else{ if (caracter == '\r') {/*analizadorLexico.informe("ERROR linea " + (analizadorLexico.get_num_lineas()) + " - Caracter \" " + "PUUUUUUUUTTTTOOOOOOOO");*/
                                                                                                                    //+ Clasificador.traducir(caracter) + " \" (# " + (int)caracter + ") no válido.");
                        }else{  analizadorLexico.informe("linea " + (analizadorLexico.get_num_lineas()) + " - Caracter \" " + Clasificador.traducir(caracter) + " \" (# " + (int)caracter + ") no válido.", Mensaje.INF);}
                  }
    }

    // Metodos generales privados.

    private void agregarCaracter(char caracter){
        buffer = buffer + caracter;
    }

    private void retroceder_archivo(char caracter) throws IOException{
        if(caracter == '\n')
            analizadorLexico.decrementar_num_lineas();
        managerArchivo.retroceder();
    }

    private void vaciarBuffer(){
        buffer = "";
    }

    private void eliminarUltimoCaracter(){
        buffer = buffer.substring(0, buffer.length()-1);
    }
}
